package com.tecklab.demo.utils;


import com.alibaba.fastjson.JSON;
import org.apache.http.NameValuePair;
import org.apache.http.client.utils.URIBuilder;
import org.apache.http.message.BasicNameValuePair;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.ResponseEntity;
import org.springframework.util.MultiValueMap;
import org.springframework.util.concurrent.ListenableFuture;
import org.springframework.web.client.AsyncRestTemplate;
import org.springframework.web.client.RestTemplate;

import java.net.MalformedURLException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

public class HttpUtils {

    protected static Logger log = LoggerFactory.getLogger(HttpUtils.class);

    private static RestTemplate restTemplate;

    private static AsyncRestTemplate asyncRestTemplate;

    private static boolean logEnable = false;

    public static void setRestTemplate(RestTemplate restTemplate) {
        HttpUtils.restTemplate = restTemplate;
    }

    public static void setAsyncRestTemplate(AsyncRestTemplate asyncRestTemplate) {
        HttpUtils.asyncRestTemplate = asyncRestTemplate;
    }

    public static void setLogEnable(boolean logEnable) {
        HttpUtils.logEnable = logEnable;
    }

    /**
     * @param url 带拼接参数
     * @return
     */
    public static String get(String url) {
        return get(url, null, null);
    }

    /**
     * @param url
     * @param uriParams url参数，可以为空
     * @return
     */
    public static String get(String url, Map<String, Object> uriParams) {
        return get(url, null, uriParams);
    }

    /**
     * url拼接参数
     *
     * @param url：不带参数，无占位符
     * @param headers
     * @param uriParams     url参数，可以为空
     */
    public static String get(String url, HttpHeaders headers, Map<String, Object> uriParams) {
        String urlWithQueryParams = getUrlWithQueryParams(url, uriParams);
        ResponseEntity<String> result = restTemplate.exchange(urlWithQueryParams, HttpMethod.GET, createHttpEntity(headers), String.class, uriParams);
        String body = result.getBody();
        if (logEnable) {
            log.info("http [GET] request 请求成功, urlWithQueryParams=[{}], response body=[{}]", urlWithQueryParams, body);
        }

        return body;
    }

    /**
     * 构造带拼接参数的url
     *
     * @param url
     * @param uriParams
     * @return
     */
    private static String getUrlWithQueryParams(String url, Map<String, Object> uriParams) {
        URI uri = null;
        try {
            URL a = new URL(url);
            List<NameValuePair> paramList = new ArrayList<>(uriParams.size());
            uriParams.forEach((key, value) -> paramList.add(new BasicNameValuePair(key, String.valueOf(value))));
            uri = new URIBuilder()
                    .setScheme(a.getProtocol())
                    .setHost(a.getHost())
                    .setPort(a.getPort())
                    .setPath(a.getPath())
                    .setParameters(paramList)
                    .build();
        } catch (MalformedURLException e) {
            throw new RuntimeException(e.getMessage(), e);
        } catch (URISyntaxException e) {
            throw new RuntimeException(e.getMessage(), e);
        }

        url = uri.toString();

//        StringBuilder queryParams = new StringBuilder(url + "?");
//        uriParams.forEach((key, value) -> queryParams.append(key).append("=").append("{").append(key).append("}").append("&"));
//        url = queryParams.substring(0, queryParams.lastIndexOf("&"));
//        log.debug("UrlTemplate is :{}", url);

        return url;
    }

    /**
     * 构造HttpEntity
     *
     * @param headers
     * @return
     */
    private static HttpEntity createHttpEntity(HttpHeaders headers) {
        return createHttpEntity(headers, null);
    }

    /**
     * 构造HttpEntity
     *
     * @param headers
     * @return
     */
    private static HttpEntity createHttpEntity(MultiValueMap<String, String> headers, Object requestBody) {
        HttpEntity httpEntity = new HttpEntity(requestBody, headers);
        return httpEntity;
    }

    /**
     * @param url       不带参数，无占位符
     * @param uriParams
     * @return
     */
    public static String post(String url, Map<String, Object> uriParams) {
        return post(url, null, uriParams);
    }

    /**
     * @param url：不带参数，无占位符
     * @param headers       可以为空
     * @param uriParams     url参数，可以为空
     * @return
     */
    public static String post(String url, HttpHeaders headers, Map<String, Object> uriParams) {
        String urlWithQueryParams = getUrlWithQueryParams(url, uriParams);
        ResponseEntity<String> result = restTemplate.exchange(getUrlWithQueryParams(url, uriParams),
                HttpMethod.POST, createHttpEntity(headers), String.class, uriParams);
        String body = result.getBody();
        if (logEnable) {
            log.info("http [POST] request 请求成功, urlWithQueryParams=[{}], response body=[{}]", urlWithQueryParams, body);
        }

        return body;
    }

    /**
     * body传参
     *
     * @param url
     * @param headers
     * @param requestBody
     * @return
     */
    public static <T> T post(String url, HttpHeaders headers, Object requestBody, Class<T> responseType) {
        ResponseEntity<T> result = restTemplate.exchange(url, HttpMethod.POST, createHttpEntity(headers, requestBody), responseType);
        T responseBody = result.getBody();
        if (logEnable) {
            log.info("http [POST] request, url=[{}], response body=[{}]", url, JSON.toJSONString(requestBody));
        }

        return responseBody;
    }

    /**
     * @param url 带拼接参数
     * @return
     */
    public static ListenableFuture<ResponseEntity<String>> asyncGet(String url) {
        return asyncGet(url, null, null);
    }

    /**
     * @param url
     * @param uriParams url参数，可以为空
     * @return
     */
    public static ListenableFuture<ResponseEntity<String>> asyncGet(String url, Map<String, Object> uriParams) {
        return asyncGet(url, null, uriParams);
    }

    /**
     * url拼接参数
     *
     * @param url：不带参数，无占位符
     * @param headers
     * @param uriParams     url参数，可以为空
     */
    public static ListenableFuture<ResponseEntity<String>> asyncGet(String url, HttpHeaders headers, Map<String, Object> uriParams) {
        ListenableFuture<ResponseEntity<String>> futureResult = asyncRestTemplate.exchange(getUrlWithQueryParams(url, uriParams), HttpMethod.GET, createHttpEntity(headers), String.class, uriParams);

        futureResult.addCallback(result -> {
            if (logEnable) {
                log.info("http [asyncGet] 请求成功, url=[{}], params=[{}], response=[{}]", url, JSON.toJSONString(uriParams), JSON.toJSONString(result.getBody()));
            }
        }, (e) -> {
            if (logEnable) {
                log.info("http [asyncGet] 请求失败, url=[{}], params=[{}]", url, JSON.toJSONString(uriParams), e);
            }
        });

        return futureResult;
    }

    /**
     * @param url       不带参数，无占位符
     * @param uriParams
     * @return
     */
    public static ListenableFuture<ResponseEntity<String>> asyncPost(String url, Map<String, Object> uriParams) {
        return asyncPost(url, null, uriParams);
    }

    /**
     * @param url：不带参数，无占位符
     * @param headers       可以为空
     * @param uriParams     url参数，可以为空
     * @return
     */
    public static ListenableFuture<ResponseEntity<String>> asyncPost(String url, HttpHeaders headers, Map<String, Object> uriParams) {
        ListenableFuture<ResponseEntity<String>> futureResult = asyncRestTemplate.exchange(getUrlWithQueryParams(url, uriParams),
                HttpMethod.POST, createHttpEntity(headers), String.class, uriParams);

        futureResult.addCallback(result -> {
            if (logEnable) {
                log.info("http [asyncPost] 请求成功, url=[{}], params=[{}], response=[{}]", url, JSON.toJSONString(uriParams), result.getBody());
            }
        }, (e) -> {
            if (logEnable) {
                log.info("http [asyncPost] 请求失败, url=[{}], params=[{}]", url, JSON.toJSONString(uriParams), e);
            }
        });

        return futureResult;
    }

    /**
     * @param url
     * @param headers
     * @param requestBody
     * @param responseType
     * @param <T>
     * @return
     */
    public static <T> ListenableFuture<ResponseEntity<T>> asyncPost(String url, HttpHeaders headers, Object requestBody, Class<T> responseType) {
        ListenableFuture<ResponseEntity<T>> futureResult = asyncRestTemplate.exchange(url, HttpMethod.POST, createHttpEntity(headers, requestBody), responseType);
        futureResult.addCallback(result -> {
            if (logEnable) {
                log.info("http [asyncPost] 请求成功, url=[{}], params=[{}], response=[{}]", url, JSON.toJSONString(requestBody), JSON.toJSONString(result.getBody()));
            }
        }, (e) -> {
            if (logEnable) {
                log.info("http [asyncPost] 请求失败, url=[{}], params=[{}]", url, JSON.toJSONString(requestBody), e);
            }
        });

        return futureResult;
    }

}
